public class CaseCategoryToSolution 
{
	//This class is designed to add the originating case category to the solution.
	//The class will be invoked from a solution After Update trigger.
	//We must be very careful to avoid dipping too deeply into the case table and
	//blowing our SOQL query size limit of 1000. It's tempting to limit the case query to 1000,
	//but if we handle all cases correctly we won't have to.
	public static void AssignSolutionCategory(solution[] solutions)
	{
		//This set is created to hold the solution Id's passed from the trigger. We can use the set
		//as a filter when we query other tables that contain solution Id's
		set<Id> solutionIdSet = New set<Id>();
		for (Solution s : solutions) solutionIdSet.add(s.Id);
		//If the solution already has a category associated with it, we don't want to assign another one.
		//this set creates a filter of all solutions that already have categories.
		set<id> solutionsWithCategories = New set<id>();
		for (CategoryData cd : [Select RelatedSobjectId from categoryData where RelatedSObjectId in :solutionIdSet])
		{
			solutionsWithCategories.add(cd.RelatedSobjectId);		
		}
		//We don't proceed unless we have solutions that need categories
		If (solutionsWithCategories.size() < solutionIdSet.size())
		{
			//This map lets us relate solutions to cases, which will help when creating the category based on the
			//case feature area
			Map<Id,string> solutionCaseMap = New Map<Id,string>();
			//The last loop in the class needs a collection with a sequential numerical index, therefore we make a list
			List<id> solutionIdList = New List<id>();
			//we'll need to be able to filter the big giant case table by only case id's associated with solutions we're 
			//working with. This set holds those Id's.
			set<id> caseIdset = New set<Id>();
			for (CaseSolution cs : [Select SolutionId,CaseId from casesolution where SolutionId in :solutionIdSet AND SolutionId NOT IN :solutionsWithCategories])
			{
				//We have to ensure we only have one case match per solution. there will be an exception if we
				//try to add a duplicate Id to the map.
				if (solutionCaseMap.containsKey(cs.SolutionId)==false) if(cs.SolutionId!= null) if(cs.CaseId != null)
				{
					solutionCaseMap.put(cs.SolutionId,cs.CaseId);
					solutionIdList.add(cs.SolutionId);
					caseIdset.add(cs.caseId);
				}
			}
			If (solutionCaseMap.size() > 0)
			{
				Map<Id,string> caseFeatureAreaMap = New Map<id, string>();
				for (Case c : [Select Id,Feature_Area__c from case where id in :caseIdset])
				{
					caseFeatureAreaMap.put(c.id, c.Feature_Area__c);
				}
				List<CategoryNode> categoryNodeList = New List<CategoryNode>();
				for (CategoryNode cn : [Select Id,MasterLabel from categorynode])
				{
					categoryNodeList.add(cn);
				}
				List<CategoryData> category = New List<CategoryData>();
				for (integer x = 0; x < categoryNodeList.size(); x++)
				{
					for (integer i = 0; i < solutionIdList.size(); i++)
					{
						If (caseFeatureAreaMap.get(solutionCaseMap.get(solutionIdList[i])) == categoryNodeList[x].MasterLabel)
						{
							CategoryData cd = new CategoryData();
							cd.CategoryNodeId =	categoryNodeList[x].id;
							cd.RelatedSobjectId = solutionIdList[i];
							category.add(cd);
						}
					}
				}
				insert category;
			}
		}	
	}
}